package com.david.bluetooth.ble.musicctr

import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.Service
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothDevice
import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCharacteristic
import android.bluetooth.BluetoothGattDescriptor
import android.bluetooth.BluetoothGattServer
import android.bluetooth.BluetoothGattServerCallback
import android.bluetooth.BluetoothGattService
import android.bluetooth.BluetoothManager
import android.bluetooth.le.AdvertiseCallback
import android.bluetooth.le.AdvertiseData
import android.bluetooth.le.AdvertiseSettings
import android.bluetooth.le.BluetoothLeAdvertiser
import android.content.Intent
import android.os.IBinder
import android.os.ParcelUuid
import android.os.SystemClock
import android.util.Log
import androidx.core.app.NotificationCompat
import com.david.bluetooth.R
import java.util.Arrays
import java.util.UUID


class BleServerMusicService: Service() {
    private val TAG = "BleServerMusicService"

    private val UUID_SERVICE = UUID.fromString("10000000-0000-0000-0000-000000000000") //自定义UUID

    private val UUID_CHAR_READ_NOTIFY = UUID.fromString("11000000-0000-0000-0000-000000000000")
    private val UUID_DESC_NOTITY = UUID.fromString("11100000-0000-0000-0000-000000000000")
    private val UUID_CHAR_WRITE = UUID.fromString("12000000-0000-0000-0000-000000000000")
    private var mBluetoothLeAdvertiser: BluetoothLeAdvertiser? = null // BLE广播

    private var mBluetoothGattServer: BluetoothGattServer? = null // BLE服务端

    private var device: BluetoothDevice? = null
    private var characteristic: BluetoothGattCharacteristic? = null

    // BLE广播Callback
    private val mAdvertiseCallback: AdvertiseCallback = object : AdvertiseCallback() {
        override fun onStartSuccess(settingsInEffect: AdvertiseSettings) {
            logTv("BLE广播开启成功")
        }

        override fun onStartFailure(errorCode: Int) {
            logTv("BLE广播开启失败,错误码:$errorCode")
        }
    }


    // BLE服务端Callback
    private val mBluetoothGattServerCallback: BluetoothGattServerCallback = object : BluetoothGattServerCallback() {
        override fun onConnectionStateChange(device: BluetoothDevice, status: Int, newState: Int) {
            Log.i(TAG, String.format("onConnectionStateChange:%s,%s,%s,%s", device.name, device.address, status, newState))
            if (status == 0 && newState == 2) {
                this@BleServerMusicService.device = device

                musicBleConnect = true
            } else {
                musicBleConnect = false
            }


            onActionResultListener?.onConnectChange(musicBleConnect)


            logTv(String.format(if (status == 0) (if (newState == 2) "与[%s]连接成功" else "与[%s]连接断开") else "与[%s]连接出错,错误码:$status", device))
        }

        override fun onServiceAdded(status: Int, service: BluetoothGattService) {
            Log.i(TAG, String.format("onServiceAdded:%s,%s", status, service.uuid))
            logTv(String.format(if (status == 0) "添加服务[%s]成功" else "添加服务[%s]失败,错误码:$status", service.uuid))
        }

        override fun onCharacteristicReadRequest(device: BluetoothDevice, requestId: Int, offset: Int, characteristic: BluetoothGattCharacteristic) {
            Log.i(TAG, String.format("onCharacteristicReadRequest:%s,%s,%s,%s,%s", device.name, device.address, requestId, offset, characteristic.uuid))
            val response = "CHAR_" + (Math.random() * 100).toInt() //模拟数据
            mBluetoothGattServer!!.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, response.toByteArray()) // 响应客户端
            logTv("""
    客户端读取Characteristic[${characteristic.uuid}]:
    $response
    """.trimIndent())
        }

        override fun onCharacteristicWriteRequest(device: BluetoothDevice, requestId: Int, characteristic: BluetoothGattCharacteristic, preparedWrite: Boolean, responseNeeded: Boolean, offset: Int, requestBytes: ByteArray) {
            parseResult(this@BleServerMusicService, requestBytes)


            this@BleServerMusicService.characteristic = characteristic

            // 获取客户端发过来的数据
            val requestStr = String(requestBytes)
            Log.i(TAG, String.format("onCharacteristicWriteRequest:%s,%s,%s,%s,%s,%s,%s,%s", device.name, device.address, requestId, characteristic.uuid,
                preparedWrite, responseNeeded, offset, requestStr))
            characteristic.setValue("testing...".toByteArray())
            mBluetoothGattServer!!.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, requestBytes) // 响应客户端
            logTv("客户端写入Characteristic[${characteristic.uuid}]:$requestStr".trimIndent())
        }

        override fun onDescriptorReadRequest(device: BluetoothDevice, requestId: Int, offset: Int, descriptor: BluetoothGattDescriptor) {
            Log.i(TAG, String.format("onDescriptorReadRequest:%s,%s,%s,%s,%s", device.name, device.address, requestId, offset, descriptor.uuid))
            val response = "DESC_" + (Math.random() * 100).toInt() //模拟数据
            mBluetoothGattServer!!.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, response.toByteArray()) // 响应客户端
            logTv("""
    客户端读取Descriptor[${descriptor.uuid}]:
    $response
    """.trimIndent())
        }

        override fun onDescriptorWriteRequest(device: BluetoothDevice, requestId: Int, descriptor: BluetoothGattDescriptor, preparedWrite: Boolean, responseNeeded: Boolean, offset: Int, value: ByteArray) {

            // 获取客户端发过来的数据
            val valueStr = String(value)
            Log.i(TAG, String.format("onDescriptorWriteRequest:%s,%s,%s,%s,%s,%s,%s,%s", device.name, device.address, requestId, descriptor.uuid,
                preparedWrite, responseNeeded, offset, valueStr))
            mBluetoothGattServer!!.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value) // 响应客户端
            logTv("""
    客户端写入Descriptor[${descriptor.uuid}]:
    $valueStr
    """.trimIndent())

            val characteristic = descriptor.characteristic

            // 简单模拟通知客户端Characteristic变化
            if (Arrays.toString(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE) == valueStr) { //是否开启通知
                Thread {
                    for (i in 0..4) {
                        SystemClock.sleep(3000)
                        val response = "CHAR_" + (Math.random() * 100).toInt() //模拟数据
                        characteristic.setValue(response)
                        mBluetoothGattServer?.notifyCharacteristicChanged(device, characteristic, false)
                        logTv("""
    通知客户端改变Characteristic[${characteristic.uuid}]:
    $response
    """.trimIndent())
                    }
                }.start()
            }
        }

        override fun onExecuteWrite(device: BluetoothDevice, requestId: Int, execute: Boolean) {
            Log.i(TAG, String.format("onExecuteWrite:%s,%s,%s,%s", device.name, device.address, requestId, execute))
        }

        override fun onNotificationSent(device: BluetoothDevice, status: Int) {
            Log.i(TAG, String.format("onNotificationSent:%s,%s,%s", device.name, device.address, status))
        }

        override fun onMtuChanged(device: BluetoothDevice, mtu: Int) {
            Log.i(TAG, String.format("onMtuChanged:%s,%s,%s", device.name, device.address, mtu))
        }
    }

    private lateinit var characteristicWrite: BluetoothGattCharacteristic


    override fun onCreate() {
        super.onCreate()
    }

    private fun startAdvertising() {
        val bluetoothManager = getSystemService(BLUETOOTH_SERVICE) as BluetoothManager
        //        BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
        //        BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter();
        val bluetoothAdapter = BluetoothAdapter.getDefaultAdapter()

        // ============启动BLE蓝牙广播(广告) =================================================================================
        //广播设置(必须)
        val settings = AdvertiseSettings.Builder()
            .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY) //广播模式: 低功耗,平衡,低延迟
            .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH) //发射功率级别: 极低,低,中,高
            .setConnectable(true) //能否连接,广播分为可连接广播和不可连接广播
            .build()
        //广播数据(必须，广播启动就会发送)
        val advertiseData = AdvertiseData.Builder()
            .setIncludeDeviceName(true) //包含蓝牙名称
            .setIncludeTxPowerLevel(true) //包含发射功率级别
            .addManufacturerData(1, byteArrayOf(23, 33)) //设备厂商数据，自定义
            .build()
        //扫描响应数据(可选，当客户端扫描时才发送)
        val scanResponse = AdvertiseData.Builder()
            .addManufacturerData(2, byteArrayOf(66, 66)) //设备厂商数据，自定义
            .addServiceUuid(ParcelUuid(UUID_SERVICE)) //服务UUID
            //                .addServiceData(new ParcelUuid(UUID_SERVICE), new byte[]{2}) //服务数据，自定义
            .build()
        mBluetoothLeAdvertiser = bluetoothAdapter.bluetoothLeAdvertiser
        mBluetoothLeAdvertiser?.startAdvertising(settings, advertiseData, scanResponse, mAdvertiseCallback)

        // 注意：必须要开启可连接的BLE广播，其它设备才能发现并连接BLE服务端!
        // =============启动BLE蓝牙服务端=====================================================================================
        val service = BluetoothGattService(UUID_SERVICE, BluetoothGattService.SERVICE_TYPE_PRIMARY)
        //添加可读+通知characteristic
        val characteristicRead = BluetoothGattCharacteristic(UUID_CHAR_READ_NOTIFY,
            BluetoothGattCharacteristic.PROPERTY_READ or BluetoothGattCharacteristic.PROPERTY_NOTIFY, BluetoothGattCharacteristic.PERMISSION_READ)
        characteristicRead.addDescriptor(BluetoothGattDescriptor(UUID_DESC_NOTITY, BluetoothGattCharacteristic.PERMISSION_WRITE))
        service.addCharacteristic(characteristicRead)
        //添加可写characteristic
        characteristicWrite = BluetoothGattCharacteristic(UUID_CHAR_WRITE,
            BluetoothGattCharacteristic.PROPERTY_WRITE, BluetoothGattCharacteristic.PERMISSION_WRITE)
        service.addCharacteristic(characteristicWrite)
        if (bluetoothManager != null) mBluetoothGattServer = bluetoothManager.openGattServer(this, mBluetoothGattServerCallback)
        mBluetoothGattServer!!.addService(service)
    }

    override fun onBind(intent: Intent?): IBinder? {
        return null
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        when(intent?.getIntExtra(MUSIC_ACTION_SERVICE_ACTION_KEY, -1)) {
            MUSIC_ACTION_SERVICE_BLE_ADVERTISING -> {
                if (!musicBleConnect) {
                    startAdvertising()

                    logTv("start advertising...")
                }
            }
            MUSIC_ACTION_SERVICE_SEND_DATA -> {//server端向client端发送数据
                // TODO: 回传数据
                characteristic?.value = intent.getByteArrayExtra(MUSIC_ACTION_SERVICE_DATA_KEY)
                mBluetoothGattServer?.notifyCharacteristicChanged(device, characteristic, false)


                logTv("send data: ${intent.getByteArrayExtra(MUSIC_ACTION_SERVICE_DATA_KEY)}")
            }
            MUSIC_ACTION_SERVICE_CLOSE -> {
                // TODO: 关闭连接
                if (mBluetoothLeAdvertiser != null) mBluetoothLeAdvertiser!!.stopAdvertising(mAdvertiseCallback)
                if (mBluetoothGattServer != null) mBluetoothGattServer!!.close()


                logTv("connect close...")
            }
        }

        startNotification()
        return START_STICKY
    }

    /**
     * 启动一个前台通知，但通知栏会显示一个通知栏
     */
    private fun startNotification() {
        val builder: NotificationCompat.Builder = NotificationCompat.Builder(this, "server")
        builder.setContentTitle("musicBleServer")
        builder.setContentText("musicBleServer running...")
        builder.setSmallIcon(R.mipmap.ic_logo)
        builder.setContentIntent(PendingIntent.getActivity(this, 0, Intent(this, MusicServerActivity::class.java), PendingIntent.FLAG_IMMUTABLE))

        val silentChannel = NotificationChannel(
            "server",
            "musicBleServer",
            NotificationManager.IMPORTANCE_HIGH
        )
        silentChannel.name = "ble server is running..."
        silentChannel.setSound(null, null)
        silentChannel.enableVibration(false)
        val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
        manager.createNotificationChannel(silentChannel)

        // 这里两个通知使用同一个id且必须按照这个顺序后调用startForeground
        val id = 2
        //                        NotificationManagerCompat.from(this).notify(id, builder.build());
        startForeground(id, builder.build())
    }

    private fun logTv(msg: String) {
        Log.e(TAG, msg)

        tips.append(msg).append("\n").append("\n")

        onActionResultListener?.onTipsChange(tips.toString())
    }

    companion object{
        const val MUSIC_ACTION_SERVICE_ACTION_KEY = "MUSIC_ACTION_SERVICE_ACTION_KEY"
        const val MUSIC_ACTION_SERVICE_DATA_KEY = "MUSIC_ACTION_SERVICE_DATA_KEY"

        const val MUSIC_ACTION_SERVICE_BLE_ADVERTISING = 0
        const val MUSIC_ACTION_SERVICE_SEND_DATA = 1
        const val MUSIC_ACTION_SERVICE_CLOSE = 2

        var musicBleConnect = false

        var tips = StringBuilder()

        var onActionResultListener: OnTipsChangeListener? = null
    }
}

interface OnTipsChangeListener{
    fun onConnectChange(musicBleConnect: Boolean)
    fun onTipsChange(tips: String)
}